package zgame.bussiness;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Vector;

import zgame.bean.PhomInfo;
import zgame.bean.RankItem;
import zgame.bean.Table;
import zgame.bean.User;
import zgame.socket.DataPackage;

public class GameTalaBussiness extends GameComponent {
  public ArrayList<Vector<Integer>> userCards;
  public Vector<Integer> taiLuot;
  public boolean isTaiLuot;
  public boolean isWaitTaiLuot;
  public int taiLuotFault;
  public int taiLuotIndex;
  private int[] firedCards;
  private ArrayList<Vector<Integer>> eatenCards;
  private ArrayList<Vector<PhomInfo>> phoms;
  private ArrayList<Vector<PhomInfo>> phomAn;
  private int turn;
  private int bocTurn;
  private int guiTurn;
  private int totalUser;
  private int registeredUser;
  private int bid;
  private Vector<Integer> boBai;
  private User[] users;
  private Table currentTable;
  private static final int DELIVER_CARD_HEADER = 1;
  private static final int FIRED_CARD_HEADER = 2;
  private static final int BOC_BAI_HEADER = 3;
  private static final int AN_BAI_HEADER = 4;
  private static final int SEND_TOTAL_HEADER = 5;
  private static final int INVALID_ACTION = 6;
  private static final int VALID_ACTION = 7;
  private static final int HA_PHOM_DONE_HEADER = 8;
  private static final int HA_PHOM_HEADER = 9;
  private static final int HOST_CARD_HEADER = 10;
  private static final int TAKE_TURN = 11;
  private static final int REQUEST_CARD_HEADER = 12;
  private static final int TURN_ORDER = 13;
  private static final int RANDOM_CARD = 14;
  private static final int HA_PHOM_XONG_HEADER = 15; // Ket thuc ha
  private static final int HA_PHOM_SAI_HEADER = 16; // Phom ha khong hop le
  private static final int HA_PHOM_TIMEOUT_HEADER = 17;
  private static final int HOST_CARD_FAILED = 18;
  private static final int HOST_CARD_DONE = 19;
  private static final int HOST_CARD_SEND_HEADER = 20;
  private static final int OUT_TABLE = 21;

  private int latestFiredIndex;
  private int[] diemThuong;
  private int[] diemThang;
  private int[] finalPoint;
  private int readytakeTurn = 0;
  public static int zeroPoint;
  private int leftPoint = 0;
  private int latestFiredCard = 0;
  private DataPackage turnOrder = null;
  private int totalFired;
  private Hashtable<String, Integer> thuTuHaBai;
  private int userHaBai;// la so thu tu ha bai cua user, so nay tang dan len
  private ArrayList<Vector<Integer>> guiBaiId;
  private User firstPlay = null;
  private ArrayList<User> interruptedUser;
  private int[] numberOfGet;
  private User latestFiredUser;
  private boolean feedAndQuit = false;
  private ArrayList<Vector<DataPackage>> guiBaiString;
  private boolean[] guiU;

  public GameTalaBussiness(Table table) {
    super(table);
  }

  public void init() {
    startGameSession(table);
  }

  /**
   * đặt lại lượt đi cho user
   * 
   * @param value
   */
  private void setTurn(int value) {
    turn = value;
  }

  /**
   * đặt lại lượt bốc cho user
   * 
   * @param value
   */
  private void setBocTurn(int value) {
    bocTurn = value;
  }

  /**
   * chuyển lượt bốc
   */
  private void changeBocTurn() {
    bocTurn++;
    if (bocTurn >= totalUser) {
      bocTurn = 0;
    }
  }

  public void setTurn(User turn) {
    for (int i = 0; i < users.length; i++) {
      if (users[i].getUsername().equals(turn.getUsername())) {
        this.turn = i;
        return;
      }
    }
    this.turn = 0;
  }

  /**
   * chuyển lượt đi
   */
  private void changeTurn() {
    turn++;
    if (turn >= totalUser) {
      turn = 0;
    }
  }

  private void setGuiTurn(int index) {
    guiTurn = index;
  }

  private void changeGuiTurn() {
    guiTurn++;
    if (guiTurn >= totalUser) {
      guiTurn = 0;
    }
  }

  public int getGuiTurn() {
    return guiTurn;
  }

  /**
   * hàm này được gọi khi user ấn start-game
   */
  public void startGameSession(Table table) {
    userHaBai = 0;
    readytakeTurn = 0;
    latestFiredCard = 0;
    currentTable = table;
    isTaiLuot = false;
    isWaitTaiLuot = false;
    taiLuotIndex = 0;
    taiLuotFault = 0;
    totalUser = 0;
    users = new User[table.getConcurrentUser()];
    Iterator<User> iter = table.getUsers().iterator();
    thuTuHaBai = new Hashtable<String, Integer>();

    if (currentTable.getLastWinUser() == null) {
      firstPlay = table.getTableMaster();
    } else {
      if (table.getLastWinUser() != null) {
        for (User user : table.getUsers()) {
          if (user.getUsername().equals(table.getLastWinUser())) {
            firstPlay = user;
            break;
          }
        }
      }
    }
    while (iter.hasNext()) {
      users[totalUser] = iter.next();
      if (users[totalUser].equals(firstPlay)) {
        setTurn(totalUser);
        setBocTurn(totalUser);
        changeBocTurn();
      }
      totalUser++;
    }
    registeredUser = totalUser;
    zeroPoint = 1000;
    bid = table.getBid();
    diemThuong = new int[totalUser];
    numberOfGet = new int[totalUser];
    diemThang = new int[totalUser];
    finalPoint = new int[totalUser];
    taiLuot = new Vector<Integer>();
    firedCards = new int[totalUser];
    guiU = new boolean[totalUser];
    latestFiredIndex = -1;
    latestFiredUser = null;
    interruptedUser = new ArrayList<User>();
    userCards = new ArrayList<Vector<Integer>>();
    phoms = new ArrayList<Vector<PhomInfo>>();
    phomAn = new ArrayList<Vector<PhomInfo>>();
    eatenCards = new ArrayList<Vector<Integer>>();
    guiBaiId = new ArrayList<Vector<Integer>>();
    guiBaiString = new ArrayList<Vector<DataPackage>>();
    totalFired = 0;
    for (int i = 0; i < totalUser; i++) {
      numberOfGet[i] = 0;
      finalPoint[i] = 0;
      diemThuong[i] = 0;
      firedCards[i] = 0;
      diemThang[i] = getCeiling(bid);
      guiU[i] = false;
      userCards.add(new Vector<Integer>());
      guiBaiString.add(new Vector<DataPackage>());
      guiBaiId.add(new Vector<Integer>());
      phoms.add(new Vector<PhomInfo>());
      phomAn.add(new Vector<PhomInfo>());
      eatenCards.add(new Vector<Integer>());
    }
    boBai = new Vector<Integer>();
    chiaBai();
    turnOrder = buildTurnOrderString();
  }

  public void pauseGame(Table table) {
    throw new UnsupportedOperationException("Not supported yet.");
  }

  /**
   * sinh ra chuỗi chứa thứ tự được đi trong bàn, từ người đi đầu tiên
   * 
   * @return
   */
  private DataPackage buildTurnOrderString() {
    DataPackage movePackage = createGamePackage(TURN_ORDER);
    movePackage.putString(firstPlay.getUsername());
    int i, ownerIndex = 0;

    for (i = 0; i < totalUser; i++) {
      if (users[i].equals(firstPlay)) {
        ownerIndex = i;
        ownerIndex = ownerIndex + 1 < totalUser ? ownerIndex + 1 : 0;
        break;
      }
    }
    movePackage.putInt(totalUser - 1);
    for (i = 0; i < totalUser - 1; i++) {
      movePackage.putString(users[ownerIndex].getUsername());
      ownerIndex = ownerIndex + 1 < totalUser ? ownerIndex + 1 : 0;
    }
    return movePackage;
  }

  /**
   * sau mỗi lần ăn cây, thực hiện san lại bài đánh
   * 
   * @param pos
   */
  public void sanBai() {
    int temp = firedCards[totalUser - 1];
    for (int i = totalUser - 1; i >= 0; i--) {
      if (i == 0) {
        firedCards[i] = temp;
      } else {
        firedCards[i] = firedCards[i - 1];
      }
    }
  }

  public boolean isInTaiLuotList(int index) {
    if (taiLuot.contains(index)) {
      return true;
    }
    return false;
  }

  /**
	 * 
	 */
  @Override
  protected void onActionPerform(User user, DataPackage inputDataPackage) {
    int userIndex = 0;
    // tim index cua user
    for (int i = 0; i < totalUser; i++) {
      if (users[i].getUsername().equals(user.getUsername())) {
        userIndex = i;
        break;
      }
    }
    
    int header = inputDataPackage.getHeader();
    switch (header) {
    case REQUEST_CARD_HEADER:
      boolean ukhan = false;
      readytakeTurn++;
      sendKetQuaChiaBai(user.getUsername());
      if (readytakeTurn == totalUser) {
        for (int i = 0; i < totalUser; i++) {
          if (checkUKhan(i)) {
            ukhan = true;
            List<RankItem> gameResult = new Vector<RankItem>();
            for (int j = 0; j < totalUser; j++) {
              DataPackage movePackage = createGamePackage(SEND_TOTAL_HEADER);
              movePackage.putString(users[j].getUsername());
              if (i == j) {
                movePackage.putInt(0);
                movePackage.putInt(-1);
                diemThang[j] += (totalUser - 1) * (totalUser + 1) * bid;
                gameResult.add(new RankItem(users[j], 0, diemThuong[j], diemThang[j]));
              } else {
                diemThang[j] -= (totalUser + 1) * bid;
                movePackage.putInt(-1);
                movePackage.putInt(4);
                movePackage.putInt(0);
                gameResult.add(new RankItem(users[j], 4, diemThuong[j], diemThang[j]));
              }
              users[i].server.write(movePackage);
            }
            setTurn(users[i]);
            releaseResource();
            table.endGame();
            break;
          }
        }
        if (ukhan == false) {
          DataPackage movePackage = createGamePackage(TAKE_TURN);
          movePackage.putString(firstPlay.getUsername());
          sendAction(movePackage);
        }
      }
      break;
    case TURN_ORDER:
      sendPrivateAction(turnOrder, user);
      break;
    case FIRED_CARD_HEADER:
      int card = inputDataPackage.nextInt();
      latestFiredCard = card;
      System.out.println("Nguoi choi " + user.getUsername() + " danh quan bai " + card);
      if (checkDanhBai(card, userIndex) && turn == userIndex) {
        totalFired++;
        DataPackage movePackage = createGamePackage(VALID_ACTION);
        movePackage.putInt(FIRED_CARD_HEADER);
        movePackage.putString(user.getUsername());
        sendPrivateAction(movePackage, user);
        
        movePackage = createGamePackage(FIRED_CARD_HEADER);
        movePackage.putInt(card);
        movePackage.putString(user.getUsername());
        sendAction(movePackage, user);
        latestFiredUser = user;
        latestFiredIndex = userIndex;
        userCards.get(userIndex).removeElement(latestFiredCard);
        firedCards[userIndex]++;
        // check ha bai
        if (firedCards[userIndex] >= 4) {
          if (phoms.get(userIndex).size() > 0) {
            finalPoint[userIndex] -= (latestFiredCard % 13 + 1);
          }
          // đến lượt hạ, thông báo cho user
          if (totalFiredCards() >= totalUser * 4 || checkHetBai()) {
            for (int i = 0; i < totalUser; i++) {
              if (phoms.get(i).size() > 0) {
                int size = userCards.get(i).size();
                int point = 0;
                for (int j = 0; j < size; j++) {
                  point += userCards.get(i).get(j) % 13 + 1;
                }
                finalPoint[i] = point;
              }
            }
            List<RankItem> gameResult = new Vector<RankItem>();
            int songuoimom = 0;
            for (int i = 0; i < totalUser; i++) {
              if (finalPoint[i] >= 1000)
                songuoimom++;
            }
            for (int i = 0; i < totalUser; i++) {
              int numberOfCompare = 0;
              for (int k = 0; k < totalUser; k++) {
                if (k != i) {
                  if (finalPoint[i] > finalPoint[k]) {
                    numberOfCompare++;
                  }
                  // diem bang nhau thi so sanh ha truoc ha sau
                  else if (finalPoint[i] == finalPoint[k]) {
                    if ((Integer) thuTuHaBai.get(users[i].getUsername()) > (Integer) thuTuHaBai.get(users[k].getUsername())) {
                      numberOfCompare++;
                    }
                  }
                }
              }
              if (numberOfCompare == 0) {
                // neu la nguoi thang cuoc
                int factor = 0;
                for (int l = 1; l < totalUser - songuoimom; l++) {
                  factor += l;
                }
                diemThang[i] += factor * bid;
                if (finalPoint[i] >= 1000) {
                  diemThang[i] += (songuoimom - 1) * totalUser * bid;
                } else {
                  diemThang[i] += songuoimom * totalUser * bid;
                }
                diemThang[i] += (registeredUser - totalUser) * totalUser * bid;
                setTurn(users[i]);
              } else {
                // neu la mom
                if (finalPoint[i] >= 1000) {
                  diemThang[i] -= totalUser * bid;
                } else {
                  diemThang[i] -= numberOfCompare * bid;
                }
              }
              DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
              movePackage1.putString(users[i].getUsername());
              if (phoms.get(i).size() > 0) {
                if (finalPoint[i] == 0) {
                  movePackage1.putInt(0);
                  movePackage1.putInt(0);
                  gameResult.add(new RankItem(users[i], 0, diemThuong[i], diemThang[i]));
                } else {
                  movePackage1.putInt(finalPoint[i]);
                  movePackage1.putInt(numberOfCompare);
                  int leftCardSize = userCards.get(i).size();
                  movePackage1.putInt(leftCardSize);
                  for (int t = 0; t < leftCardSize; t++) {
                    movePackage1.putInt(userCards.get(i).get(t));
                  }
                  gameResult.add(new RankItem(users[i], numberOfCompare, diemThuong[i], diemThang[i]));
                }
              } else {
                movePackage1.putInt(-1);
                movePackage1.putInt(numberOfCompare);
                int leftCardSize = userCards.get(i).size();
                movePackage1.putInt(leftCardSize);
                for (int t = 0; t < leftCardSize; t++) {
                  movePackage1.putInt(userCards.get(i).get(t));
                }
                gameResult.add(new RankItem(users[i], numberOfCompare, diemThuong[i], diemThang[i]));
              }
              sendAction(movePackage1);
            }
            
            for (int i = totalUser; i < registeredUser; i++) {
              DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
              movePackage1.putString(users[i].getUsername());
              movePackage1.putInt(-1);
              movePackage1.putInt(4);
              movePackage1.putInt(0);
              sendAction(movePackage1);
              gameResult.add(new RankItem(users[i], 4, diemThuong[i], diemThang[i]));
            }
            interruptedUser.removeAll(interruptedUser);
            releaseResource();
            table.endGame();
          } else {
            changeTurn();
            setBocTurn(turn);
            DataPackage movePackage1 = createGamePackage(TAKE_TURN);
            movePackage1.putString(users[turn].getUsername());
            sendAction(movePackage1);
          }
        } else {
          changeTurn();
          setBocTurn(turn);
          DataPackage movePackage1 = createGamePackage(TAKE_TURN);
          movePackage1.putString(users[turn].getUsername());
          sendAction(movePackage1);
        }
      } else {
        DataPackage movePackage = createGamePackage(INVALID_ACTION);
        movePackage.putInt(FIRED_CARD_HEADER);
        movePackage.putString(user.getUsername());
        sendPrivateAction(movePackage, user);
      }
      break;
    case BOC_BAI_HEADER:
      if (user.getUsername().equals(users[bocTurn].getUsername()) && userCards.get(bocTurn).size() < 10) {
        numberOfGet[turn]++;
        DataPackage movePackage = createGamePackage(BOC_BAI_HEADER);
        movePackage.putString(user.getUsername());
        sendAction(movePackage, user);
        Random random = new Random();
        int ran = random.nextInt(boBai.size());
        userCards.get(userIndex).add(boBai.get(ran));
        movePackage = createGamePackage(BOC_BAI_HEADER);
        movePackage.putString(user.getUsername());
        movePackage.putInt(boBai.get(ran));
        boBai.removeElementAt(ran);
        movePackage.putString(users[userIndex].getUsername());
        sendPrivateAction(movePackage, users[userIndex]);

        if (checkU(userIndex)) {
          if (guiU[userIndex]) {
            for (int i = 0; i < guiBaiString.get(userIndex).size(); i++) {
              // ////////////- Cho nay can xem lai
              sendAction(guiBaiString.get(userIndex).get(i));
            }
          }
          sendAction(buildHaBaiString(userIndex, true));

          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          
          if (isTaiLuot && isInTaiLuotList(userIndex)) {
            diemThang[taiLuotFault] -= (totalUser - 1) * (totalUser + 1) * bid;
            diemThang[userIndex] += (totalUser - 1) * (totalUser + 1) * bid;
            for (int i = 0; i < totalUser; i++) {
              DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
              movePackage1.putString(users[i].getUsername());
              if (users[i].equals(user)) {
                movePackage1.putInt(0);
                movePackage1.putInt(0);
              } else {
                movePackage1.putInt(-1);
                movePackage1.putInt(4);
                movePackage1.putInt(0);
              }
              sendAction(movePackage1);
            }
            for (int i = totalUser; i < registeredUser; i++) {
              DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
              movePackage1.putString(users[i].getUsername());
              movePackage1.putInt(-1);
              movePackage1.putInt(4);
              movePackage1.putInt(0);
              sendAction(movePackage1);
            }
          } else {
            for (int i = 0; i < totalUser; i++) {
              DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
              movePackage1.putString(users[i].getUsername());
              if (users[i] == user) {
                diemThang[i] += (totalUser - 1) * (totalUser + 1) * bid;
                movePackage1.putInt(0);
                movePackage1.putInt(0);
              } else {
                diemThang[i] -= (totalUser + 1) * bid;
                movePackage1.putInt(-1);
                movePackage1.putInt(4);
                movePackage1.putInt(0);
              }
              sendAction(movePackage1);
            }
            for (int i = totalUser; i < registeredUser; i++) {
              DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
              movePackage1.putString(users[i].getUsername());
              movePackage1.putInt(-1);
              movePackage1.putInt(4);
              movePackage1.putInt(0);
              sendAction(movePackage1);
            }
          }
          List<RankItem> gameResult = new Vector<RankItem>();
          for (int i = 0; i < totalUser; i++) {
            if (users[i] == user) {
              gameResult.add(new RankItem(users[i], 0, diemThuong[i], diemThang[i]));
              setTurn(users[i]);
            } else {
              gameResult.add(new RankItem(users[i], 4, diemThuong[i], diemThang[i]));
            }
          }
          for (int i = totalUser; i < registeredUser; i++) {
            gameResult.add(new RankItem(users[i], 4, diemThuong[i], diemThang[i]));
          }
          interruptedUser.removeAll(interruptedUser);
          releaseResource();
          table.endGame();
        } else {
          if (firedCards[userIndex] >= 3) {
            userHaBai++;
            if (thuTuHaBai.containsKey(users[userIndex].getUsername())) {
              thuTuHaBai.remove(users[userIndex].getUsername());
            }
            thuTuHaBai.put(users[userIndex].getUsername(), userHaBai);
            sendAction(buildHaBaiString(userIndex, false));
            setGuiTurn(userIndex);
          }
          changeBocTurn();
        }
      }
      break;
    case AN_BAI_HEADER:
      Vector<Integer> selectedCards = new Vector<Integer>();
      int numberOfSelected = inputDataPackage.nextInt();
      for (int i = 0; i < numberOfSelected; i++) {
        selectedCards.addElement(inputDataPackage.nextInt());
      }
      if (checkAn(userIndex, latestFiredCard, selectedCards, false)) {
        totalFired--;
        int beforeIndex = turn - 1 >= 0 ? turn - 1 : totalUser - 1;
        DataPackage movePackage = createGamePackage(VALID_ACTION);
        movePackage.putInt(AN_BAI_HEADER);
        movePackage.putInt(latestFiredCard);
        movePackage.putString(feedAndQuit ? latestFiredUser.getUsername() : users[beforeIndex].getUsername());
        movePackage.putString(user.getUsername());
        sendPrivateAction(movePackage, user);
        movePackage = createGamePackage(AN_BAI_HEADER);
        movePackage.putInt(latestFiredCard);
        movePackage.putString(feedAndQuit ? latestFiredUser.getUsername() : users[beforeIndex].getUsername());
        feedAndQuit = false;
        movePackage.putString(user.getUsername());
        sendAction(movePackage, user);
        PhomInfo phom = new PhomInfo();
        phom.addCard(latestFiredCard);
        for (int i = 0; i < numberOfSelected; i++) {
          phom.addCard(selectedCards.elementAt(i));
        }
        phomAn.get(userIndex).add(phom);
        eatenCards.get(userIndex).add(latestFiredCard);
        userCards.get(userIndex).add(latestFiredCard);
        boolean caychot = true;
        for (int i = 0; i < totalUser; i++) {
          if (firedCards[i] != 3) {
            caychot = false;
            break;
          }

        }
        if (firedCards[latestFiredIndex] >= 4 || caychot) {
          diemThuong[latestFiredIndex] -= totalUser * bid;
          diemThuong[userIndex] += totalUser * bid;
        } else {
          diemThuong[latestFiredIndex] -= bid;
          diemThuong[userIndex] += bid;
        }

        firedCards[latestFiredIndex]--;

        if (firedCards[latestFiredIndex] == 3) {
          isWaitTaiLuot = true;
        }

        if (isWaitTaiLuot) {
          isWaitTaiLuot = false;
          if (firedCards[latestFiredIndex] < 4) {

            System.out.println("tai luot cho " + users[latestFiredIndex].getUsername());
            isTaiLuot = true;
            if (!isInTaiLuotList(latestFiredIndex)) {
              taiLuot.add(latestFiredIndex);
            }
            taiLuotFault = latestFiredIndex;
            taiLuotIndex++;
            if (taiLuotIndex >= totalUser) {
              taiLuotIndex = 0;
            }
          }
        }
        sanBai();
        if (eatenCards.get(userIndex).size() >= 3) {
          diemThang[latestFiredIndex] -= (totalUser - 1) * (totalUser + 1) * bid;
          diemThang[userIndex] += (totalUser - 1) * (totalUser + 1) * bid;

          System.out.println(">>>>>>>>>> U den");
          sendAction(buildHaBaiString(userIndex, true));
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          for (int i = 0; i < totalUser; i++) {
            DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
            movePackage1.putString(users[i].getUsername());
            if (users[i] == user) {
              movePackage1.putInt(0);
              movePackage1.putInt(0);

            } else {
              movePackage1.putInt(-1);
              movePackage1.putInt(4);
              movePackage1.putInt(0);
            }
            sendAction(movePackage1);
          }
          for (int i = totalUser; i < registeredUser; i++) {
            DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
            movePackage1.putString(users[i].getUsername());
            movePackage1.putInt(-1);
            movePackage1.putInt(4);
            movePackage1.putInt(0);
            sendAction(movePackage1);
          }
          List<RankItem> gameResult = new Vector<RankItem>();
          for (int i = 0; i < totalUser; i++) {
            if (i == turn) {
              setTurn(users[i]);
              gameResult.add(new RankItem(users[i], 0, diemThuong[i], diemThang[i]));
            } else {
              gameResult.add(new RankItem(users[i], 4, diemThuong[i], diemThang[i]));
            }
          }
          for (int i = totalUser; i < registeredUser; i++) {
            gameResult.add(new RankItem(users[i], 4, diemThuong[i], diemThang[i]));
          }
          interruptedUser.removeAll(interruptedUser);
          releaseResource();
          table.endGame();
        } else {
          if (checkU(userIndex)) {
            if (guiU[userIndex]) {
              for (int i = 0; i < guiBaiString.get(userIndex).size(); i++) {
                // /////////////////-------- Can xem lai cho nay
                sendAction(guiBaiString.get(userIndex).get(i));
              }
            }
            sendAction(buildHaBaiString(userIndex, true));
            
            try {
              Thread.sleep(1000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
            
            if (isTaiLuot && isInTaiLuotList(turn)) {
              diemThang[taiLuotFault] -= (totalUser - 1) * (totalUser + 1) * bid;
              diemThang[userIndex] += (totalUser - 1) * (totalUser + 1) * bid;
              System.out.println(">>>>>>>>>> U den tai luot");
              for (int i = 0; i < totalUser; i++) {
                DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
                movePackage1.putString(users[i].getUsername());
                if (users[i].equals(user)) {
                  movePackage1.putInt(0);
                  movePackage1.putInt(0);
                } else {
                  movePackage1.putInt(-1);
                  movePackage1.putInt(4);
                  movePackage1.putInt(0);
                }
                sendAction(movePackage1);
              }
              for (int i = totalUser; i < registeredUser; i++) {
                DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
                movePackage1.putString(users[i].getUsername());
                movePackage1.putInt(-1);
                movePackage1.putInt(4);
                movePackage1.putInt(0);
                sendAction(movePackage1);
              }
            } else {
              for (int i = 0; i < totalUser; i++) {
                DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
                movePackage1.putString(users[i].getUsername());
                if (users[i] == user) {
                  diemThang[i] += (totalUser - 1) * (totalUser + 1) * bid;
                  movePackage1.putInt(0);
                  movePackage1.putInt(0);
                } else {
                  diemThang[i] -= (totalUser + 1) * bid;
                  movePackage1.putInt(-1);
                  movePackage1.putInt(4);
                  movePackage1.putInt(0);
                }
                sendAction(movePackage1);
              }
              for (int i = totalUser; i < registeredUser; i++) {
                DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
                movePackage1.putString(users[i].getUsername());
                movePackage1.putInt(-1);
                movePackage1.putInt(4);
                movePackage1.putInt(0);
                sendAction(movePackage1);
              }
            }
            List<RankItem> gameResult = new Vector<RankItem>();
            for (int i = 0; i < totalUser; i++) {
              if (users[i] == user) {
                gameResult.add(new RankItem(users[i], 0, diemThuong[i], diemThang[i]));
                setTurn(users[i]);
              } else {
                gameResult.add(new RankItem(users[i], 4, diemThuong[i], diemThang[i]));
              }
            }
            for (int i = totalUser; i < registeredUser; i++) {
              gameResult.add(new RankItem(users[i], 4, diemThuong[i], diemThang[i]));
            }
            interruptedUser.removeAll(interruptedUser);
            releaseResource();
            table.endGame();
          } else if (firedCards[userIndex] >= 3) {
            userHaBai++;
            if (thuTuHaBai.containsKey(users[userIndex].getUsername())) {
              thuTuHaBai.remove(users[userIndex].getUsername());
            }
            thuTuHaBai.put(users[userIndex].getUsername(), userHaBai);
            sendAction(buildHaBaiString(userIndex, false));
            setGuiTurn(userIndex);
          }
        }
      } // neu khong an dc thi thong bao cho user
      else {
        DataPackage movePackage = createGamePackage(INVALID_ACTION);
        movePackage.putInt(AN_BAI_HEADER);
        movePackage.putString(users[turn].getUsername());
        sendPrivateAction(movePackage, users[turn]);
      }
      break;
    case RANDOM_CARD:
      Vector<Integer> tmp = (Vector<Integer>) userCards.get(userIndex).clone();
      Vector<PhomInfo> phom = getPhomVertical(tmp, userIndex, false);
      tmp = AscendingSort(tmp);
      boolean found = false;
      for (int i = 0; i < tmp.size(); i++) {
        int id = tmp.get(i);
        if (checkDanhBai(id, userIndex)) {
          for (int j = 0; j < phom.size(); j++) {
            PhomInfo info = phom.get(j);
            if (info.contains(id)) {
              found = true;
              break;
            }
          }
          if (!found) {
            DataPackage movePackage = createGamePackage(RANDOM_CARD);
            movePackage.putInt(id);
            movePackage.putString(users[userIndex].getUsername());
            sendPrivateAction(movePackage, users[userIndex]);
            break;
          } else {
            found = false;
          }
        }
      }
      break;
    case HA_PHOM_XONG_HEADER:
      if (totalFiredCards() >= 3 * totalUser) {
        Vector<Integer> selectedCards1 = new Vector<Integer>();
        Vector<PhomInfo> infoTemp = new Vector<PhomInfo>();
        int i, j;
        boolean eatCount = true;
        int numberOfSelected1 = inputDataPackage.nextInt();
        if (numberOfSelected1 == 0) {
          if (phoms.get(userIndex).size() <= 0) {
            zeroPoint++;
            finalPoint[userIndex] = zeroPoint;
          } else {
            guiBaiId.get(userIndex).removeAllElements();
            DataPackage movePackage = createGamePackage(HOST_CARD_HEADER);
            movePackage.putString(users[userIndex].getUsername());
            int countSize = 0;
            for (i = 0; i < userCards.get(userIndex).size(); i++) {
              DataPackage phomCuoi = getHostableList(userCards.get(userIndex).get(i), userIndex, false);
              if (phomCuoi != null) {
                countSize++;
              }
            }
            movePackage.putInt(countSize);
            for (i = 0; i < userCards.get(userIndex).size(); i++) {
              DataPackage phomCuoi = getHostableList(userCards.get(userIndex).get(i), userIndex, false);
              if (phomCuoi != null) {
                guiBaiId.get(userIndex).add(userCards.get(userIndex).get(i));
                movePackage.putInt(userCards.get(userIndex).get(i));
              }
            }
            movePackage.putString(users[userIndex].getUsername());
            sendPrivateAction(movePackage, users[userIndex]);
          }
        } else {
          for (i = 0; i < numberOfSelected1; i++) {
            selectedCards1.addElement(inputDataPackage.nextInt());
          }
          for (i = 0; i < eatenCards.get(userIndex).size(); i++) {
            if (!selectedCards1.contains(eatenCards.get(userIndex).get(i))) {
              if (phoms.get(userIndex).size() == 0) {
                eatCount = false;
              }
            }
          }
          // nếu các phỏm chứa đủ con bài đã ăn
          if (eatCount) {
            System.out.println("cac phom da du cac con an");
            Vector<PhomInfo> selectedForm = new Vector<PhomInfo>();
            Vector<PhomInfo> result = getListPhom(selectedCards1);
            Vector<Integer> copy = (Vector<Integer>) selectedCards1.clone();
            for (i = 0; i < result.size(); i++) {
              PhomInfo info = (PhomInfo) result.get(i);
              for (j = 0; j < info.size(); j++) {
                copy.removeElement(info.getCard(j));
              }
            }
            // nếu các phom get được trùng với tập bài gửi lên
            if (copy.size() == 0) {
              System.out.println("sau khi get phom tap bai co size = 0");
              switch (result.size()) {
              case 1:
                System.out.println("tim dc 1 phom");
                selectedForm.add(result.get(0));
                break;
              case 2:
                System.out.println("tim dc 2 phom");
                int crossCard = isCrossPhom(result.get(0), result.get(1));
                if (crossCard == -1) {
                  System.out.println("hai phom ko giao nhau");
                  selectedForm.add(result.get(0));
                  selectedForm.add(result.get(1));
                } else {
                  infoTemp = splitForm(result.get(0), result.get(1));
                  if (infoTemp.size() != 0) {
                    selectedForm.add(infoTemp.get(0));
                    selectedForm.add(result.get(1));
                  } else {
                    System.out.println("hai phom giao nhau nhung ko hop le");
                  }
                }
                break;
              default:
                boolean isCross;
                // chon loc phom uu tien phom ngang
                System.out.println("co it nhat 3 phom tim dc");
                int resultSize = result.size();
                for (i = 0; i < resultSize - 1; i++) {
                  isCross = false;

                  for (j = i + 1; j < resultSize; j++) {
                    if (isCrossPhom(result.get(i), result.get(j)) != -1) {
                      System.out.println("trong 3 phom tim dc thi co it nhat hai phom giao nhau");
                      isCross = true;
                      infoTemp = splitForm(result.get(i), result.get(j), result.get(0).isVertical());
                      if (infoTemp.size() == 0) {
                        // selectedForm.add(infoTemp.get(0));
                        // numAdd++;
                        result.get(i).removeCard(isCrossPhom(result.get(i), result.get(j)));
                      }
                    }
                  }
                  if (!isCross) {
                    selectedForm.add(result.get(i));
                  } else {
                    if (isCaDoc(result.get(i).getCards()) || isCaNgang(result.get(i).getCards())) {
                      selectedForm.add(result.get(i));
                    }
                  }
                }
                selectedForm.add(result.get(resultSize - 1));
                break;
              }
              if (selectedForm.size() == 0) {
                System.out.println("khong chon dc phom nao");
                DataPackage movePackage = createGamePackage(HA_PHOM_SAI_HEADER);
                movePackage.putString(users[userIndex].getUsername());
                sendPrivateAction(movePackage, users[userIndex]);
              } else {
                // trường hợp duy nhất hạ phỏm đúng
                DataPackage movePackage = createGamePackage(HA_PHOM_DONE_HEADER);
                movePackage.putInt(selectedForm.size());
                for (i = 0; i < selectedForm.size(); i++) {
                  PhomInfo info = selectedForm.get(i);
                  for (j = 0; j < info.size(); j++) {
                    userCards.get(userIndex).removeElement(info.getCard(j));
                  }
                  movePackage.putInt(info.size());
                  for (j = 0; j < info.size(); j++) {
                    movePackage.putInt(info.getCard(j));
                  }
                  phoms.get(userIndex).add(selectedForm.get(i));
                }
                movePackage.putString(users[userIndex].getUsername());
                sendAction(movePackage);
                // tinh diem
                guiBaiId.get(userIndex).removeAllElements();
                movePackage = createGamePackage(HOST_CARD_HEADER);
                movePackage.putString(users[userIndex].getUsername());
                int countSize = 0;
                for (i = 0; i < userCards.get(userIndex).size(); i++) {
                  DataPackage phomCuoi = getHostableList(userCards.get(userIndex).get(i), userIndex, false);
                  if (phomCuoi != null) {
                    countSize++;
                  }
                }
                movePackage.putInt(countSize);
                for (i = 0; i < userCards.get(userIndex).size(); i++) {
                  DataPackage phomCuoi = getHostableList(userCards.get(userIndex).get(i), userIndex, false);
                  if (phomCuoi != null) {
                    movePackage.putInt(userCards.get(userIndex).get(i));
                    guiBaiId.get(userIndex).add(userCards.get(userIndex).get(i));
                  }
                }
                movePackage.putString(user.getUsername());
                sendPrivateAction(movePackage, user);
                phomAn.get(userIndex).removeAllElements();
                eatenCards.get(userIndex).removeAllElements();
              }
            }
            // sau khi get hết phỏm mà vẫn dư it nhất một con bài
            else {
              System.out.println("gui len thua bai");
              DataPackage movePackage = createGamePackage(HA_PHOM_SAI_HEADER);
              movePackage.putString(users[userIndex].getUsername());
              sendPrivateAction(movePackage, users[userIndex]);
            }
          }
          // các phỏm vẫn thiếu con bài đã ăn
          else {
            System.out.println("thieu con bai an");
            DataPackage movePackage = createGamePackage(HA_PHOM_SAI_HEADER);
            movePackage.putString(users[userIndex].getUsername());
            sendPrivateAction(movePackage, users[userIndex]);
          }
        }
      } else {
        DataPackage movePackage = createGamePackage(HA_PHOM_SAI_HEADER);
        movePackage.putString(users[userIndex].getUsername());
        sendPrivateAction(movePackage, users[userIndex]);
      }
      break;
    case HA_PHOM_TIMEOUT_HEADER:
      if (totalFiredCards() >= 3 * totalUser || firedCards[userIndex] >= 3) {
        DataPackage habai = buildHaBaiString(userIndex, true);
        sendAction(habai);
        guiBaiId.get(userIndex).removeAllElements();
        for (int i = 0; i < userCards.get(userIndex).size(); i++) {
          DataPackage phomCuoi = getHostableList(userCards.get(userIndex).get(i), userIndex, true);
          if (phomCuoi != null) {
            guiBaiId.get(userIndex).add(userCards.get(userIndex).get(i));
            sendAction(phomCuoi);
          }
        }
      }
      break;
    case HOST_CARD_SEND_HEADER:
      if (totalFiredCards() >= totalUser * 3 && getGuiTurn() == userIndex) {
        changeGuiTurn();
        Vector<Integer> selectedCards2 = new Vector<Integer>();
        int numberOfSelected2 = inputDataPackage.nextInt();
        if (numberOfSelected2 > 0) {
          for (int m = 0; m < numberOfSelected2; m++) {
            card = inputDataPackage.nextInt();
            if (!selectedCards2.contains(card)) {
              selectedCards2.addElement(card);
            }
          }
          if (selectedCards2.size() == 0) {
            DataPackage movePackage = createGamePackage(HOST_CARD_FAILED);
            movePackage.putString(users[userIndex].getUsername());
            sendPrivateAction(movePackage, users[userIndex]);
          } else {
            for (int t = 0; t < selectedCards2.size(); t++) {
              card = selectedCards2.get(t);
              DataPackage strgui = getHostableList(card, userIndex, true);
              if (strgui != null) {
                sendAction(strgui);
                finalPoint[userIndex] -= (card % 13 + 1);
                userCards.get(userIndex).removeElement(card);
              }
            }
          }
        }
      } else {
        DataPackage movePackage = createGamePackage(HOST_CARD_FAILED);
        movePackage.putString(users[userIndex].getUsername());
        sendPrivateAction(movePackage, users[userIndex]);
      }
      break;
    }
  }

  @SuppressWarnings("unchecked")
  private DataPackage buildHaBaiString(int userIndex, boolean autoHost) {
    DataPackage movePackage;
    if (!autoHost) {
      movePackage = createGamePackage(HA_PHOM_HEADER);
      Vector<Integer> tempCard = (Vector<Integer>) userCards.get(userIndex).clone();
      Vector<PhomInfo> finalPhom = getMinPoint(tempCard, eatenCards.get(userIndex));
      int bestPhomSize = finalPhom.size();
      movePackage.putInt(bestPhomSize);
      for (int i = 0; i < bestPhomSize; i++) {
        PhomInfo info = finalPhom.elementAt(i);
        for (int j = 0; j < info.size(); j++) {
          tempCard.removeElement(info.getCard(j));
        }
        movePackage.putInt(info.size());
        for (int j = 0; j < info.size(); j++) {
          movePackage.putInt(info.getCard(j));
        }
      }
      movePackage.putString(users[userIndex].getUsername());
    } else {
      movePackage = createGamePackage(HA_PHOM_DONE_HEADER);
      Vector<Integer> tempCard = (Vector<Integer>) userCards.get(userIndex).clone();
      Vector<PhomInfo> finalPhom = getMinPoint(tempCard, eatenCards.get(userIndex));
      int bestPhomSize = finalPhom.size();
      movePackage.putInt(bestPhomSize);
      for (int i = 0; i < bestPhomSize; i++) {
        PhomInfo info = finalPhom.elementAt(i);
        for (int j = 0; j < info.size(); j++) {
          userCards.get(userIndex).removeElement(info.getCard(j));
        }
        phoms.get(userIndex).add(info);
        movePackage.putInt(info.size());
        for (int j = 0; j < info.size(); j++) {
          movePackage.putInt(info.getCard(j));
        }
      }
      movePackage.putString(users[userIndex].getUsername());
    }
    return movePackage;
  }

  /**
   * chia bài cho các user và đẩy vào các vector
   */
  private void chiaBai() {
    int ran = 0;
    for (int i = 0; i < 52; i++) {
      boBai.add(i);
    }
    Random random = new Random();
    for (int i = 0; i < totalUser * 9; i++) {
      ran = random.nextInt(boBai.size());
      int id = boBai.get(ran);
      userCards.get(i % totalUser).add(id);
      boBai.removeElement(id);
    }
    ran = random.nextInt(boBai.size());
    int id = boBai.get(ran);
    userCards.get(turn).add(id);
    boBai.removeElement(id);
  }

  /**
   * sap xep tap quan bai theo gia tri quan bai tang dan
   * 
   * @param cards
   */
  private static Vector<Integer> HorizontalSort(Vector<Integer> cards) {
    if (cards == null) {
      return null;
    }
    int size = cards.size();
    for (int i = 0; i < size - 1; i++) {
      for (int j = i + 1; j < size; j++) {
        int info = cards.elementAt(i);
        int infoTemp = cards.elementAt(j);
        if ((info % 13) > (infoTemp % 13)) {
          cards.setElementAt(infoTemp, i);
          cards.setElementAt(info, j);
        }
      }
    }
    return cards;
  }

  /**
   * sap xep tap quan bai dua vao theo thu tu id tang dan
   * 
   * @param cards
   */
  private static Vector<Integer> VerticalSort(Vector<Integer> cards) {
    if (cards == null) {
      return null;
    }
    int size = cards.size();
    for (int i = 0; i < size - 1; i++) {
      for (int j = i + 1; j < size; j++) {
        int info = cards.elementAt(i);
        int infoTemp = cards.elementAt(j);
        if (info > infoTemp) {
          cards.setElementAt(infoTemp, i);
          cards.setElementAt(info, j);
        }
      }
    }
    return cards;
  }

  private Vector<Integer> AscendingSort(Vector<Integer> cards) {
    if (cards == null) {
      return null;
    }
    int size = cards.size();
    for (int i = 0; i < size - 1; i++) {
      for (int j = i + 1; j < size; j++) {
        int info = cards.elementAt(i);
        int infoTemp = cards.elementAt(j);
        if (info % 13 < infoTemp % 13) {
          cards.setElementAt(infoTemp, i);
          cards.setElementAt(info, j);
        }
      }
    }
    return cards;
  }

  /**
   * kiem tra tap quan bai dua vao co phai la phom cung chat
   * 
   * @param quanBais
   * @return
   */
  private static boolean isCaDoc(Vector<Integer> quanBais) {
    quanBais = VerticalSort(quanBais);
    int quanBaiLen = quanBais.size();
    if (quanBaiLen <= 2) {
      return false;
    }
    for (int i = 0; i < quanBaiLen - 1; i++) {
      if (Math.abs(quanBais.elementAt(i + 1) - quanBais.elementAt(i)) != 1) {
        return false;
      }
    }
    if ((quanBais.firstElement() / 13) != (quanBais.lastElement() / 13)) {
      return false;
    }
    return true;
  }

  /**
   * kiem tra tap quan bai dua vao co phai la phom ngang
   * 
   * @param quanBais
   * @return
   */
  private static boolean isCaNgang(Vector<Integer> quanBais) {
    int quanBaiLen = quanBais.size();
    if (quanBaiLen <= 2) {
      return false;
    }
    for (int i = 0; i < quanBaiLen - 1; i++) {
      if ((quanBais.elementAt(i) % 13) != (quanBais.elementAt(i + 1) % 13)) {
        return false;
      }
    }
    return true;
  }

  private DataPackage getHostableList(int quanBai, int index, boolean autoHost) {
    DataPackage movePackage;
    ArrayList<Vector<PhomInfo>> copyPhom = (ArrayList<Vector<PhomInfo>>) phoms.clone();
    int indexOrder = -1;
    if (thuTuHaBai.containsKey(users[index].getUsername())) {
      indexOrder = (Integer) thuTuHaBai.get(users[index].getUsername());
    }
    for (int i = 0; i < totalUser; i++) {
      int iOrder = -1;
      if (thuTuHaBai.containsKey(users[i].getUsername())) {
        iOrder = (Integer) thuTuHaBai.get(users[i].getUsername());
      }
      
      if ((iOrder > 0) && (iOrder < indexOrder)) {
        int phomSize = copyPhom.get(i).size();
        for (int j = 0; j < phomSize; j++) {
          PhomInfo phomInfo = copyPhom.get(i).get(j);
          if (!phomInfo.isVertical()) {
            Vector<Integer> checkPhom = new Vector<Integer>();
            for (int k = 0; k < phomInfo.size(); k++) {
              checkPhom.addElement(phomInfo.getCard(k));
            }
            if (!checkPhom.contains(quanBai)) {
              checkPhom.addElement(quanBai);
            }
            if (isCaDoc(checkPhom) || isCaNgang(checkPhom)) {
              // them con bai gui vao phom cua user
              if (!phomInfo.contains(quanBai)) {
                phomInfo.addCard(quanBai);
              }
              if (!phoms.get(i).get(j).contains(quanBai) && autoHost) {
                phoms.get(i).get(j).addCard(quanBai);
              }
              movePackage = createGamePackage(HOST_CARD_DONE);
              movePackage.putString(users[index].getUsername());
              movePackage.putInt(quanBai);
              movePackage.putInt(j);
              movePackage.putString(users[i].getUsername());
              return movePackage;
            }
          }
        }
        
        for (int j = 0; j < phomSize; j++) {
          PhomInfo phomInfo = copyPhom.get(i).get(j);
          if (phomInfo.isVertical()) {
            Vector<Integer> checkPhom = new Vector<Integer>();
            for (int k = 0; k < phomInfo.size(); k++) {
              checkPhom.addElement(phomInfo.getCard(k));
            }
            if (!checkPhom.contains(quanBai)) {
              checkPhom.addElement(quanBai);
            }
            if (isCaDoc(checkPhom) || isCaNgang(checkPhom)) {
              // them con bai gui vao phom cua user
              if (!phomInfo.contains(quanBai)) {
                phomInfo.addCard(quanBai);
              }
              if (!phoms.get(i).get(j).contains(quanBai) && autoHost) {
                phoms.get(i).get(j).addCard(quanBai);
              }
              
              movePackage = createGamePackage(HOST_CARD_DONE);
              movePackage.putString(users[index].getUsername());
              movePackage.putInt(quanBai);
              movePackage.putInt(j);
              movePackage.putString(users[i].getUsername());
              return movePackage;
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * tra ve cac phom tim dc ,uu tien tim phom ngang truoc
   */
  @SuppressWarnings("unchecked")
  private Vector<PhomInfo> getPhomHorizontal(Vector<Integer> cardVector, int to, boolean isGuiBai) {
    Vector<PhomInfo> Userphoms = new Vector<PhomInfo>();
    Vector<Integer> cards = (Vector<Integer>) cardVector.clone();
    int begin = 0;
    int end = 0;
    int cardSize = cards.size();
    int i, j;
    Vector<Integer> remove = new Vector<Integer>();
    cards = HorizontalSort(cards);
    for (i = 0; i < cardSize - 1; i++) {
      int truoc = cards.get(i + 1);
      int sau = cards.get(i);
      if (truoc % 13 != sau % 13) {
        // neu co phom
        if (end - begin >= 2) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            remove.addElement(cards.get(j));
            phomInfo.addCard(cards.get(j));
          }
          Userphoms.addElement(phomInfo);
        }
        begin = i + 1;
        end = i + 1;
      } else {
        end++;
        if ((i == cards.size() - 2) && (end - begin >= 2)) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            remove.addElement(cards.get(j));
            phomInfo.addCard(cards.get(j));
          }
          Userphoms.addElement(phomInfo);
        }
      }
    }
    
    // remove phom ngang
    for (i = 0; i < remove.size(); i++) {
      cards.removeElement(remove.elementAt(i));
    }
    cards = VerticalSort(cards);
    end = 0;
    begin = 0;
    remove.clear();
    cardSize = cards.size();
    for (i = 0; i < cardSize - 1; i++) {
      int truoc = cards.get(i + 1);
      int sau = cards.get(i);
      if ((truoc - sau != 1) || (truoc / 13 != sau / 13)) {
        // neu co phom
        if (end - begin >= 2) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            remove.addElement(cards.get(j));
            phomInfo.addCard(cards.get(j));
          }
          Userphoms.addElement(phomInfo);
        }
        begin = i + 1;
        end = i + 1;
      } else {
        end++;
        if ((i == cards.size() - 2) && (end - begin >= 2)) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            remove.addElement(cards.get(j));
            phomInfo.addCard(cards.get(j));
          }
          Userphoms.addElement(phomInfo);
        }
      }
    }
    // remove phom doc
    for (i = 0; i < remove.size(); i++) {
      cards.removeElement(remove.elementAt(i));
    }
    leftPoint = 0;
    cardSize = cards.size();

    for (i = 0; i < cardSize; i++) {
      leftPoint += cards.elementAt(i) % 13 + 1;
    }
    return Userphoms;
  }

  @SuppressWarnings("unchecked")
  private Vector<PhomInfo> getPhomVertical(Vector<Integer> cardVector, int to, boolean isGuiBai) {
    Vector<PhomInfo> Userphoms = new Vector<PhomInfo>();
    Vector<Integer> cards = (Vector<Integer>) cardVector.clone();
    int begin = 0;
    int end = 0;
    Vector<Integer> remove = new Vector<Integer>();
    cards = VerticalSort(cards);
    int cardSize = cards.size();
    int i, j;
    for (i = 0; i < cardSize - 1; i++) {
      int truoc = cards.get(i + 1);
      int sau = cards.get(i);
      if ((truoc - sau != 1) || (truoc / 13 != sau / 13)) {
        // neu co phom
        if (end - begin >= 2) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            remove.addElement(cards.get(j));
            phomInfo.addCard(cards.get(j));
          }
          Userphoms.addElement(phomInfo);
        }
        begin = i + 1;
        end = i + 1;
      } else {
        end++;
        if ((i == cards.size() - 2) && (end - begin >= 2)) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            remove.addElement(cards.get(j));
            phomInfo.addCard(cards.get(j));
          }
          Userphoms.addElement(phomInfo);
        }
      }
    }
    // remove phom doc
    for (i = 0; i < remove.size(); i++) {
      cards.removeElement(remove.elementAt(i));
    }
    cards = HorizontalSort(cards);
    end = 0;
    begin = 0;
    remove.clear();
    cardSize = cards.size();
    for (i = 0; i < cardSize - 1; i++) {
      int truoc = cards.get(i + 1);
      int sau = cards.get(i);
      if (truoc % 13 != sau % 13) {
        // neu co phom
        if (end - begin >= 2) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            remove.addElement(cards.get(j));
            phomInfo.addCard(cards.get(j));
          }
          Userphoms.addElement(phomInfo);
        }
        begin = i + 1;
        end = i + 1;
      } else {
        end++;
        if ((i == cards.size() - 2) && (end - begin >= 2)) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            remove.addElement(cards.get(j));
            phomInfo.addCard(cards.get(j));
          }
          Userphoms.addElement(phomInfo);
        }
      }
    }
    // remove phom ngang
    for (i = 0; i < remove.size(); i++) {
      cards.removeElement(remove.elementAt(i));
    }
    leftPoint = 0;
    cardSize = cards.size();
    for (i = 0; i < cardSize; i++) {

      leftPoint += cards.get(i) % 13 + 1;
    }
    return Userphoms;
  }

  /**
   * check xem cay bai dua vao va cac cay bai nhac len co tao thanh mot phom
   * 
   * @param cardId
   * @return
   */
  private boolean checkAn(int userIndex, int cardId, Vector<Integer> selectedCard, boolean tolerateMultiple) {
    if (selectedCard.size() < 2) {
      return false;
    }
    if (userCards.get(userIndex).size() >= 10) {
      return false;
    }
    if (!tolerateMultiple) {
      if (!checkMultipleGetCard(selectedCard, userIndex)) {
        return false;
      }
    }
    Vector<Integer> quanBais = new Vector<Integer>();
    for (int i = 0; i < selectedCard.size(); i++) {
      quanBais.addElement(selectedCard.elementAt(i));
    }
    quanBais.addElement(cardId);

    if (isCaNgang(quanBais) || isCaDoc(quanBais)) {
      return true;
    }
    return false;
  }

  /**
   * check xem bai da u chua
   * 
   * @param cardVector
   * @return
   */
  private boolean checkU(int to) {
    Vector<Integer> cardClone = (Vector<Integer>) userCards.get(to).clone();
    Vector<PhomInfo> ret = getMinPoint(userCards.get(to), eatenCards.get(to));
    if (ret.size() >= 3) {
      return true;
    }
    for (int i = 0; i < ret.size(); i++) {
      PhomInfo info = ret.get(i);
      for (int j = 0; j < info.size(); j++) {
        cardClone.removeElement(info.getCard(j));
      }
    }
    if (cardClone.size() <= 1) {
      return true;
    }
    // kiem tra gui u
    if (firedCards[to] >= 3) {
      int count = 0;
      guiBaiId.get(to).removeAllElements();
      guiBaiString.get(to).removeAllElements();
      while (count < cardClone.size()) {
        DataPackage phomCuoi = getHostableList(cardClone.get(count), to, true);
        if (phomCuoi != null) {
          guiBaiId.get(to).add(cardClone.get(count));
          guiBaiString.get(to).add(phomCuoi);
          count = 0;
          cardClone.remove(count);
        } else {
          count++;
        }
      }
      if (cardClone.size() <= 1) {
        guiU[to] = true;
        return true;
      }
    }
    return false;
  }

  public boolean checkUKhan(int index) {
    int size = userCards.get(index).size();
    Vector<Integer> cardToCheck = userCards.get(index);
    for (int i = 0; i < size - 1; i++) {
      for (int j = i + 1; j < size; j++) {
        if (cardToCheck.get(i) % 13 == cardToCheck.get(j) % 13) {
          return false;
        }
        if (Math.abs(cardToCheck.get(i) - cardToCheck.get(j)) <= 2) {
          return false;
        }
      }
    }
    return true;
  }

  /**
   * check xem con bai client yeu cau co danh dc khong
   * 
   * @param cardId
   * @param userIndex
   * @return
   */
  @SuppressWarnings("unchecked")
  private boolean checkDanhBai(int cardId, int userIndex) {
    int i, j;
    // neu con bai ko co tren bai thi ko danh dc
    if (!userCards.get(userIndex).contains(cardId)) {
      return false;
    }
    // neu khong phai luot thi ko cho danh
    if (userIndex != turn) {
      return false;
    }
    // neu con bai da an thi ko cho danh
    int eatCardSize = eatenCards.get(userIndex).size();
    for (i = 0; i < eatCardSize; i++) {
      if (cardId == eatenCards.get(userIndex).get(i)) {
        return false;
      }
    }
    
    // neu con bai danh di da nam trong phom thi ko cho danh
    Vector<Integer> bai = (Vector<Integer>) userCards.get(userIndex).clone();
    boolean found = false;
    int phomSize = phomAn.get(userIndex).size();
    for (i = 0; i < phomSize; i++) {
      PhomInfo phom = phomAn.get(userIndex).get(i);
      found = false;
      int conBaiAn = -1;
      if (phom.contains(cardId)) {
        for (j = 0; j < eatCardSize; j++) {
          if (phom.contains(eatenCards.get(userIndex).get(j))) {
            conBaiAn = eatenCards.get(userIndex).get(j);
            break;
          }
        }
        // bo con bai di xem no co lap thanh phom khong
        bai.removeElement(cardId);
        Vector<PhomInfo> checkPhom = getPhomHorizontal(bai, userIndex, false);
        int checkPhomSize = checkPhom.size();
        for (j = 0; j < checkPhomSize; j++) {
          PhomInfo ph = (PhomInfo) checkPhom.elementAt(j);
          if (ph.contains(conBaiAn)) {
            found = true;
            break;
          }
        }
        if (!found) {
          checkPhom = getPhomVertical(bai, userIndex, false);
          checkPhomSize = checkPhom.size();
          for (j = 0; j < checkPhomSize; j++) {
            PhomInfo ph = (PhomInfo) checkPhom.elementAt(j);
            if (ph.contains(conBaiAn)) {
              found = true;
              break;
            }
          }
        }
        return found;
      }
    }
    return true;
  }

  private boolean checkMultipleGetCard(Vector<Integer> cards, int userIndex) {
    for (int i = 0; i < cards.size(); i++) {
      if (!checkDanhBai(cards.elementAt(i), userIndex)) {
        return false;
      }
    }
    return true;
  }

  private void sendPrivateAction(DataPackage dataPackage, User to) {
    to.server.write(dataPackage);
  }

  private void sendAction(DataPackage dataPackage, User from) {
    for (int i = 0; i < totalUser; i++) {
      if (!users[i].equals(from)) {
        users[i].server.write(dataPackage);
      }
    }
  }

  private void sendAction(DataPackage dataPackage) {
    for (int i = 0; i < totalUser; i++) {
      users[i].server.write(dataPackage);
    }
  }

  private void sendKetQuaChiaBai(String userName) {
    for (int i = 0; i < totalUser; i++) {
      if (users[i].getUsername().equals(userName)) {
        DataPackage movePackage = createGamePackage(DELIVER_CARD_HEADER);
        movePackage.putInt(userCards.get(i).size());
        for (int j = 0; j < userCards.get(i).size(); j++) {
          movePackage.putInt(userCards.get(i).get(j));
        }
        movePackage.putInt(turn);
        users[i].server.write(movePackage);
      }
    }
  }

  public void interruptGame(User mgUser) {
    // Khi game bi gian doan thuc hien loai user ra khoi danh sach user
    if (mgUser.equals(latestFiredUser)) {
      feedAndQuit = true;
    }
    if (!interruptedUser.contains(mgUser)) {
      interruptedUser.add(mgUser);
    }

    int interruptIndex = 0;
    User nextTurn = null;
    User currentTurn = users[turn];
    for (int i = 0; i < totalUser; i++) {
      if (users[i].getUsername().equals(mgUser.getUsername())) {
        interruptIndex = i;
        nextTurn = users[i + 1 >= totalUser ? 0 : i + 1];
        break;
      }
    }
    User interrupedUser = users[interruptIndex];
    for (int i = interruptIndex; i < totalUser - 1; i++) {
      users[i] = users[i + 1];
    }

    if (interruptIndex != totalUser - 1) {
      users[totalUser - 1] = interrupedUser;
    }
    // tru diem vi bi ngat ket noi
    diemThang[interruptIndex] -= totalUser * bid;

    List<RankItem> Result = new Vector<RankItem>();
    Result.add(new RankItem(interrupedUser, 4, diemThuong[interruptIndex], diemThang[interruptIndex]));
    if (userCards.size() != 0)
      userCards.remove(interruptIndex);
    if (eatenCards.size() != 0)
      eatenCards.remove(interruptIndex);
    if (phoms.size() != 0)
      phoms.remove(interruptIndex);
    if (phomAn.size() != 0)
      phomAn.remove(interruptIndex);

    removeElement(finalPoint, interruptIndex);
    removeElement(firedCards, interruptIndex);
    removeElement(diemThang, interruptIndex);
    removeElement(diemThuong, interruptIndex);
    if (guiBaiId.size() != 0)
      guiBaiId.remove(interruptIndex);
    totalUser--;
    if (interruptIndex < turn) {
      turn--;
    }
    if (interruptIndex < bocTurn) {
      bocTurn--;
    }
    
    if (totalUser == 1) {
      List<RankItem> gameResult = new Vector<RankItem>();
      DataPackage movePackage = createGamePackage(SEND_TOTAL_HEADER);
      movePackage.putString(users[0].getUsername());
      movePackage.putInt(0);
      movePackage.putInt(0);
      sendPrivateAction(movePackage, users[0]);
      int factor = 0;
      for (int l = 1; l < registeredUser; l++) {
        factor += l;
      }
      diemThang[0] += (registeredUser - 1) * 4 * bid;
      gameResult.add(new RankItem(users[0], 0, diemThuong[0], diemThang[0]));
      for (int i = 1; i < registeredUser; i++) {
        DataPackage movePackage1 = createGamePackage(SEND_TOTAL_HEADER);
        movePackage1.putString(users[i].getUsername());
        movePackage1.putInt(-1);
        movePackage1.putInt(4);
        movePackage1.putInt(0);
        gameResult.add(new RankItem(users[i], 4, diemThuong[i], diemThang[i]));
        sendPrivateAction(movePackage1, users[0]);
      }
      interruptedUser.removeAll(interruptedUser);

      releaseResource();
      table.endGame();
    } else if (interrupedUser.getUsername().equals(currentTurn.getUsername())) {
      for (int i = 0; i < totalUser; i++) {
        if (users[i].getUsername().equals(nextTurn.getUsername())) {
          setTurn(i);
          setBocTurn(i);
          DataPackage movePackage = createGamePackage(TAKE_TURN);
          movePackage.putString(nextTurn.getUsername());
          sendAction(movePackage);
          break;
        }
      }
    }
  }

  public int getCeiling(int bid) {
    return 5 * 3 * bid + 4 * 2 * bid;
  }

  public void removeElement(int[] vector, int index) {
    int temp = vector[index];
    if (index != totalUser - 1) {
      for (int i = index; i < totalUser - 1; i++) {
        vector[i] = vector[i + 1];
      }
      vector[totalUser - 1] = temp;
    }

  }

  public boolean checkHetBai() {
    for (int i = 0; i < totalUser; i++) {
      if (firedCards[i] < 4) {
        return false;
      }
    }
    return true;
  }

  /**
   * lấy ra tất cả các phỏm có thể được từ tập con bài truyền vào
   */
  @SuppressWarnings("unchecked")
  public static Vector<PhomInfo> getListPhom(Vector<Integer> indexUserCard) {
    Vector<Integer> cards = (Vector<Integer>) indexUserCard.clone();
    Vector<PhomInfo> Userphoms = new Vector<PhomInfo>();
    int begin = 0;
    int end = 0;
    int i, j;
    int cardSize = cards.size();
    cards = VerticalSort(cards);
    cardSize = cards.size();
    for (i = 0; i < cardSize - 1; i++) {
      int truoc = cards.get(i + 1);
      int sau = cards.get(i);
      if ((truoc - sau != 1) || (truoc / 13 != sau / 13)) {
        if (end - begin >= 2) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            phomInfo.addCard(cards.get(j));
          }
          phomInfo.setVertical(true);
          Userphoms.addElement(phomInfo);
        }
        begin = i + 1;
        end = i + 1;
      } else {
        end++;
        if ((i == cards.size() - 2) && (end - begin >= 2)) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            phomInfo.addCard(cards.get(j));
          }
          phomInfo.setVertical(true);
          Userphoms.addElement(phomInfo);
        }
      }
    }

    begin = 0;
    end = 0;
    cards = HorizontalSort(cards);
    for (i = 0; i < cardSize - 1; i++) {
      int truoc = cards.get(i + 1);
      int sau = cards.get(i);
      if (truoc % 13 != sau % 13) {
        if (end - begin >= 2) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            phomInfo.addCard(cards.get(j));
          }
          phomInfo.setVertical(false);
          Userphoms.addElement(phomInfo);
        }
        begin = i + 1;
        end = i + 1;
      } else {
        end++;
        if ((i == cards.size() - 2) && (end - begin >= 2)) {
          PhomInfo phomInfo = new PhomInfo();
          for (j = begin; j <= end; j++) {
            phomInfo.addCard(cards.get(j));
          }
          phomInfo.setVertical(false);
          Userphoms.addElement(phomInfo);
        }
      }
    }
    return Userphoms;
  }

  /**
   * tìm ra tập phỏm tốt nhất từ tập cây bài truyền vào
   * 
   * @param cards
   * @return
   */
  @SuppressWarnings("unchecked")
  public static Vector<PhomInfo> getMinPoint(Vector<Integer> cards) {
    // lấy ra danh sách tất cá các phỏm có thể
    Vector<PhomInfo> Phomfound = new Vector<PhomInfo>();
    Vector<PhomInfo> list = getListPhom(cards);
    // nếu ko có phỏm trả về rỗng
    if (list.size() == 0) {
      return Phomfound;
    }
    
    // nếu có ít nhất một phỏm
    else {
      int doc = 0, ngang = 0, i = 0;
      int size = list.size();
      // đếm số phỏm dọc và ngang
      for (i = 0; i < size; i++) {
        if (list.get(i).isVertical()) {
          doc++;
        } else
          ngang++;
      }
      // mặc định là phỏm dọc lên trước, nếu chỉ có một phỏm ngang thì cho ngang lên trước
      if (ngang == 1 && doc >= 2) {
        PhomInfo temp = list.get(0);
        list.set(0, list.get(size - 1));
        list.set(size - 1, temp);
      }

      int crosses = 0;
      for (i = 1; i < size; i++) {
        if (isCrossPhom(list.get(0), list.get(i)) != -1) {
          crosses++;
          Phomfound.addElement(list.get(i));
        }
      }
      // crosses là biến đếm phỏm đầu giao với bao nhiêu phỏm khác trong danh sách nếu chỉ giao với một phỏm
      if (crosses == 1) {
        // thực hiên remove lần lượt từng phỏm và tính điểm, phỏm nào với điểm còn lại nhỏ hơn thì lấy
        int firstPoint = 0, secondPoint = 0;
        // remove phỏm thứ nhất
        Vector<Integer> cloneCards = (Vector<Integer>) cards.clone();
        for (i = 0; i < list.get(0).size(); i++) {
          cloneCards.removeElement(list.get(0).getCard(i));
        }
        Vector<PhomInfo> recursive = getMinPoint(cloneCards);
        for (i = 0; i < recursive.size(); i++) {
          for (int k = 0; k < recursive.get(i).size(); k++) {
            cloneCards.removeElement(recursive.get(i).getCard(k));
          }
        }
        // tính điểm
        for (i = 0; i < cloneCards.size(); i++) {
          firstPoint += cloneCards.get(i) % 13 + 1;
        }
        // remove phỏm thứ hai
        cloneCards = (Vector<Integer>) cards.clone();
        for (i = 0; i < Phomfound.get(0).size(); i++) {
          cloneCards.removeElement(Phomfound.get(0).getCard(i));
        }
        Vector<PhomInfo> recursive1 = getMinPoint(cloneCards);
        for (i = 0; i < recursive1.size(); i++) {
          for (int k = 0; k < recursive1.get(i).size(); k++) {
            cloneCards.removeElement(recursive1.get(i).getCard(k));
          }
        }
        // tính điểm
        for (i = 0; i < cloneCards.size(); i++) {
          secondPoint += cloneCards.get(i) % 13 + 1;
        }
        // so sánh điểm và chọn phỏm
        if (firstPoint <= secondPoint) {
          Phomfound.removeAllElements();
          Phomfound.add(list.get(0));
        }
      }
      // nếu ko giao nhau với phỏm nào thì chọn luôn
      else if (crosses == 0) {
        Phomfound.addElement(list.get(0));
      }
      // remove các con bài chọn được
      int foundsize = Phomfound.size();
      Vector<Integer> cloneCards = (Vector<Integer>) cards.clone();
      for (i = 0; i < foundsize; i++) {
        PhomInfo info = Phomfound.get(i);
        int infosize = info.size();
        for (int j = 0; j < infosize; j++) {
          cloneCards.removeElement(info.getCard(j));
        }
      }
      // thực hiện đệ quy với các con bài còn lại
      Vector<PhomInfo> recursive = getMinPoint(cloneCards);
      int recursivesize = recursive.size();
      for (i = 0; i < recursivesize; i++) {
        Phomfound.addElement(recursive.elementAt(i));
      }
    }
    return Phomfound;
  }

  /**
   * tìm ra tập phỏm tối ưu sao cho số điểm còn lại là nhỏ nhất đồng thời thỏa
   * mãn điều kiện là chứa đủ số con bài đã ăn
   * 
   * @param cards tập con bài truyền vào
   * @param eatenCardLeft số con bài đã ăn
   * @return trả về null nếu ko thấy phỏm nào
   */
  @SuppressWarnings("unchecked")
  public Vector<PhomInfo> getMinPoint(Vector<Integer> cards, Vector<Integer> eatenCardLeft) {
    Vector<PhomInfo> ret = new Vector<PhomInfo>();
    int size;
    // nếu ko ăn con nào thì lấy ra phỏm bình thường
    if (eatenCardLeft.size() == 0 || eatenCardLeft == null) {
      Vector<PhomInfo> temp = getMinPoint(cards);
      size = temp.size();
      for (int i = 0; i < size; i++) {
        ret.addElement(temp.get(i));
      }
      return ret;
    }
    // nếu có ăn ít nhất một con
    else {
      int i = 0;
      // lấy danh sách tất cả các phỏm
      Vector<PhomInfo> Userphoms = getListPhom(cards);
      int userphomsize = Userphoms.size();
      // nếu tìm được ít nhất một phỏm
      if (userphomsize > 0) {

        Vector<PhomInfo> duplicatedPhom = new Vector<PhomInfo>();
        int eatensize = eatenCardLeft.size();
        int duplicated = 0;
        // đổi chỗ các phỏm sao cho phỏm dọc(ngang) duy nhất đứng lên đầu
        for (i = 0; i < eatensize; i++) {
          duplicatedPhom.removeAllElements();

          for (int j = 0; j < userphomsize; j++) {
            PhomInfo info = Userphoms.get(j);
            if (info.contains(eatenCardLeft.get(i))) {
              duplicated++;
            }
          }
          if (eatenCardLeft.size() >= 2 && duplicated == 2 && i != 0) {
            int buf = eatenCardLeft.get(0);
            eatenCardLeft.set(0, eatenCardLeft.get(i));
            eatenCardLeft.set(i, buf);
          }
        }

        for (i = 0; i < eatensize; i++) {
          // duplicated là biến đếm số phỏm cùng chứa một con bài ăn
          duplicated = 0;
          // duplicateIndex là vị trí của phỏm chứa con bài ăn hiện
          // tại trong vòng lặp
          int duplicatedIndex = 0;
          for (int j = 0; j < userphomsize; j++) {
            PhomInfo info = Userphoms.get(j);
            if (info.contains(eatenCardLeft.get(i))) {
              duplicated++;
              duplicatedPhom.addElement(info);
              duplicatedIndex = j;
            }
          }

          if (duplicated == 1) {
            int crossItem = -1;
            int crossPhomIndex = 0;
            // nếu chỉ có hai phỏm và số con bài trong phỏm <= 3 thì ko phải xét

            if (duplicatedPhom.get(0).size() >= 4 && userphomsize >= 2) {
              for (int m = 0; m < userphomsize; m++) {
                crossItem = isCrossPhom(Userphoms.get(m), duplicatedPhom.get(0));
                if (m != duplicatedIndex && crossItem != -1) {
                  crossPhomIndex = m;
                  break;
                }
              }
            }
            
            // nếu hai phỏm chứa con ăn giao nhau với một trong các
            // phỏm còn lại
            // remove còn bài giao và kiểm tra xem còn là phỏm ko
            if (crossItem != -1) {
              PhomInfo temp = duplicatedPhom.get(0);
              temp.removeCard(crossItem);
              if (isCaDoc(temp.getCards()) || isCaNgang(temp.getCards())) {
                duplicatedPhom.removeAllElements();
                duplicatedPhom.add(temp);
                duplicatedPhom.add(Userphoms.get(crossPhomIndex));
              }
            }
            // tìm được phỏm thì remove các con bài trong phỏm và
            // remove con bài ăn hiện tại
            Vector<Integer> cloneEatenRemove = (Vector<Integer>) eatenCardLeft.clone();
            Vector<Integer> cloneCardRemove = (Vector<Integer>) cards.clone();
            cloneEatenRemove.removeElement(eatenCardLeft.get(i));
            for (int n = 0; n < duplicatedPhom.size(); n++) {
              PhomInfo phomToRemove = duplicatedPhom.get(n);
              ret.addElement(phomToRemove);
              int phomtoremovesize = phomToRemove.size();
              for (int j = 0; j < phomtoremovesize; j++) {
                cloneCardRemove.removeElement(phomToRemove.getCard(j));
              }
            }
            // thực hiện đệ quy với số con bài còn lại và số con ăn
            // còn lại
            Vector<PhomInfo> recursive = getMinPoint(cloneCardRemove, cloneEatenRemove);
            int recursivesize = recursive.size();
            for (int j = 0; j < recursivesize; j++) {
              ret.addElement(recursive.get(j));
            }
            return ret;
          }
          
          // nếu có hai phỏm cùng chứa con ăn hiện tại thử từng phỏm sau đó tính điểm còn lại xem phỏm nào là tối ưu thì chọn
          else if (duplicated == 2) {
            Vector<Integer> cloneEatenRemove = (Vector<Integer>) eatenCardLeft.clone();
            Vector<Integer> cloneCardRemove = (Vector<Integer>) cards.clone();
            int eatenNumber1 = 0, eatenNumber2 = 0;
            for (int k = 0; k < eatensize; k++) {
              if (duplicatedPhom.get(0).contains(eatenCardLeft.get(k))) {
                eatenNumber1++;
              }
              if (duplicatedPhom.get(1).contains(eatenCardLeft.get(k))) {
                eatenNumber2++;
              }
            }
            if (eatenNumber1 == 2) {
              cloneEatenRemove.removeElement(eatenCardLeft.get(i));
              PhomInfo phomToRemove = duplicatedPhom.get(1);
              int phomtoremovesize = phomToRemove.size();
              for (int j = 0; j < phomtoremovesize; j++) {
                cloneCardRemove.removeElement(phomToRemove.getCard(j));
              }
              Vector<PhomInfo> recursive = getMinPoint(cloneCardRemove, cloneEatenRemove);
              ret.addElement(duplicatedPhom.get(1));
              for (int k = 0; k < recursive.size(); k++) {
                ret.addElement(recursive.get(k));
              }
              return ret;
            } else if (eatenNumber2 == 2) {
              cloneEatenRemove.removeElement(eatenCardLeft.get(i));
              PhomInfo phomToRemove = duplicatedPhom.get(0);
              int phomtoremovesize = phomToRemove.size();
              for (int j = 0; j < phomtoremovesize; j++) {
                cloneCardRemove.removeElement(phomToRemove.getCard(j));
              }
              Vector<PhomInfo> recursive = getMinPoint(cloneCardRemove, cloneEatenRemove);
              ret.addElement(duplicatedPhom.get(0));
              for (int k = 0; k < recursive.size(); k++) {
                ret.addElement(recursive.get(k));
              }
              return ret;
            } else {
              int firstPoint = 0, secondPoint = 0;
              cloneEatenRemove.removeElement(eatenCardLeft.get(i));
              PhomInfo phomToRemove = duplicatedPhom.get(0);
              int phomtoremovesize = phomToRemove.size();
              for (int j = 0; j < phomtoremovesize; j++) {
                cloneCardRemove.removeElement(phomToRemove.getCard(j));
              }
              Vector<PhomInfo> recursive = getMinPoint(cloneCardRemove, cloneEatenRemove);
              int recursivesize = recursive.size();
              for (int j = 0; j < recursivesize; j++) {
                PhomInfo temp = recursive.get(j);
                for (int k = 0; k < temp.size(); k++) {
                  cloneCardRemove.removeElement(temp.getCard(k));
                }
              }
              // tính điểm lần một
              for (int k = 0; k < cloneCardRemove.size(); k++) {
                firstPoint += cloneCardRemove.get(k) % 13 + 1;
              }

              cloneCardRemove = (Vector<Integer>) cards.clone();
              phomToRemove = duplicatedPhom.get(1);
              phomtoremovesize = phomToRemove.size();
              for (int j = 0; j < phomtoremovesize; j++) {
                cloneCardRemove.removeElement(phomToRemove.getCard(j));
              }
              Vector<PhomInfo> recursive1 = getMinPoint(cloneCardRemove, cloneEatenRemove);
              recursivesize = recursive1.size();
              for (int j = 0; j < recursivesize; j++) {
                PhomInfo temp = recursive1.get(j);
                int tempsize = temp.size();
                for (int k = 0; k < tempsize; k++) {
                  cloneCardRemove.removeElement(temp.getCard(k));
                }
              }
              // tính điểm lần hai
              int clonesize = cloneCardRemove.size();
              for (int k = 0; k < clonesize; k++) {
                secondPoint += cloneCardRemove.get(k) % 13 + 1;
              }
              // so sánh điểm
              if (firstPoint <= secondPoint) {
                ret.addElement(duplicatedPhom.get(0));
                for (int k = 0; k < recursive.size(); k++) {
                  ret.addElement(recursive.get(k));
                }
                return ret;
              } else {
                ret.addElement(duplicatedPhom.get(1));
                for (int k = 0; k < recursive1.size(); k++) {
                  ret.addElement(recursive1.get(k));
                }
                return ret;
              }
            }
          }
        }
      }
      
      // nếu ko tìm thấy trả về rỗng
      else {
        return ret;
      }
    }
    return ret;
  }

  /**
   * kiểm tra hai phỏm có giao nhau ko
   * 
   * @param p1
   * @param p2
   * @return
   */
  public static int isCrossPhom(PhomInfo p1, PhomInfo p2) {
    int s1 = p1.size();
    int s2 = p2.size();
    if (p1.isVertical() && p2.isVertical()) {
      return -1;
    } else if (!p1.isVertical() && !p2.isVertical()) {
      return -1;
    }
    for (int i = 0; i < s1; i++) {
      for (int j = 0; j < s2; j++) {
        if (p1.getCard(i) == p2.getCard(j)) {
          return p1.getCard(i);
        }
      }
    }
    return -1;
  }

  /**
   * tính tổng số con bài đã đánh của các user hiện tại
   */
  public int totalFiredCards() {
    int ret = 0;
    for (int i = 0; i < totalUser; i++) {
      ret += firedCards[i];
    }
    return ret;
  }

  /**
   * nếu hai phỏm param1 và param2 cùng chứa một quân bài thì tách ra hai phỏm
   * 
   * @return nếu ko tách được return null, nếu tách được return hai phỏm sau khi đã tách
   */
  public Vector<PhomInfo> splitForm(PhomInfo main, PhomInfo supplement, boolean isVertical) {
    Vector<PhomInfo> ret = new Vector<PhomInfo>();
    int crossItem = isCrossPhom(main, supplement);
    if (main.size() <= 3 && supplement.size() <= 3) {
      return ret;
    } else if (main.size() <= 3 && supplement.size() >= 4) {
      supplement.removeCard(crossItem);
      if (isCaDoc(supplement.getCards()) || isCaNgang(supplement.getCards())) {
        ret.add(main);
        return ret;
      }
    } else if (supplement.size() <= 3 && main.size() >= 4) {
      main.removeCard(crossItem);
      if (isCaDoc(main.getCards()) || isCaNgang(main.getCards())) {
        ret.add(main);
        return ret;
      }
    } else {
      if (isVertical) {
        if (main.isVertical()) {
          supplement.removeCard(crossItem);
          if (isCaDoc(supplement.getCards()) || isCaNgang(supplement.getCards())) {
            ret.add(main);
            return ret;
          }
        } else {
          main.removeCard(crossItem);
          if (isCaDoc(main.getCards()) || isCaNgang(main.getCards())) {
            ret.add(main);
            return ret;
          }
        }
      } else {
        if (main.isVertical()) {
          main.removeCard(crossItem);
          if (isCaDoc(main.getCards()) || isCaNgang(main.getCards())) {
            ret.add(main);
            return ret;
          }
        } else {
          supplement.removeCard(crossItem);
          if (isCaDoc(supplement.getCards()) || isCaNgang(supplement.getCards())) {
            ret.add(main);
            return ret;
          }
        }
      }
    }
    return ret;
  }

  public Vector<PhomInfo> splitForm(PhomInfo main, PhomInfo supplement) {
    Vector<PhomInfo> ret = new Vector<PhomInfo>();
    int crossItem = isCrossPhom(main, supplement);
    if (crossItem != -1) {
      if (!main.isVertical()) {
        supplement.removeCard(crossItem);
        if (isCaDoc(supplement.getCards()) || isCaNgang(supplement.getCards())) {
          ret.add(main);
        } else {
          supplement.addCard(crossItem);
          main.removeCard(crossItem);
          if (isCaDoc(main.getCards()) || isCaNgang(main.getCards())) {
            ret.add(main);
          }
        }
      } else {
        main.removeCard(crossItem);
        if (isCaDoc(main.getCards()) || isCaNgang(main.getCards())) {
          ret.add(main);
        } else {
          main.addCard(crossItem);
          supplement.removeCard(crossItem);
          if (isCaDoc(supplement.getCards()) || isCaNgang(supplement.getCards())) {
            ret.add(main);
          }
        }
      }
    }
    return ret;
  }

  public void releaseResource() {
    userCards.clear();
    eatenCards.clear();
    phoms.clear();
    phomAn.clear();
    thuTuHaBai.clear();
    interruptedUser.clear();
    guiBaiId.clear();
    boBai.clear();
    taiLuot.clear();
  }

  @Override
  public void detroy() {
    releaseResource();
  }

  @Override
  public void onUserLeaveTable(User user) {
    DataPackage movePackage = createGamePackage(OUT_TABLE);
    movePackage.putString(user.getUsername());
    sendAction(movePackage, user);
    interruptGame(user);
  }
}
